home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EuroCD 3
/
EuroCD 3.iso
/
Emulators
/
v2600
/
Source.lha
/
Source
/
misc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-02-10
|
10KB
|
526 lines
/*****************************************************************************
This file is part of x2600, the Atari 2600 Emulator
===================================================
Copyright 1996 Alex Hornby. For contributions see the file CREDITS.
This software is distributed under the terms of the GNU General Public
License. This is free software with ABSOLUTELY NO WARRANTY.
See the file COPYING for Details.
$Id: misc.c,v 1.4 1996/08/26 15:04:20 ahornby Exp $
Tweaked by Matthew Stroup for Amiga v2600, January 27, 1997.
******************************************************************************/
/*
* This WAS part of the x64 Commodore 64 emulator.
*
* This file contains misc funtions to help debugging.
* Included are:
* o Show numeric conversions
* o Show CPU registers
* o Show Stack contents
* o Print binary number
* o Print instruction hexas from memory
* o Print instruction from memory
* o Decode instruction
* o Find effective address for operand
* o Create a copy of string
* o Move memory
*
* sprint_opcode returns mnemonic code of machine instruction.
* sprint_binary returns binary form of given code (8bit)
*
* Written by
* Vesa-Matti Puro (vmp@lut.fi)
* Jarkko Sonninen (sonninen@lut.fi)
* Jouko Valta (jopi@stekt.oulu.fi)
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "cpu.h"
#include "macro.h"
#include "misc.h"
#include "extern.h"
#include "memory.h"
#include "asm.h"
#define HEX 1
/*
* Numeric evaluation with error checking
*
* char *s; pointer to input string
* int level; recursion level
* int mode; flag: dec/hex mode
*/
int
sconv (char *s, int level, int mode)
{
static char hexas[] = "0123456789abcdefg";
char *p = s;
int base = 0;
int result = 0, sign = 1;
int i = 0;
if (!p)
return (0);
switch (tolower (*p))
{
case '%':
p++;
base = 2;
break;
case 'o':
case '&':
p++;
base = 8;
break;
case 'x':
case '$':
p++;
base = 16;
break;
case 'u':
case 'i':
case '#':
p++;
base = 10;
break;
case '0': /* 0x 0b 0d */
if (!*++p)
return ((mode & MODE_QUERY) ? 1 : 0);
if (!isdigit (*p))
return (sconv (p, level + 1, mode));
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
base = (mode & MODE_HEX) ? 16 : 10;
break;
case 'a':
case 'c':
case 'e':
case 'f':
if (mode & MODE_HEX)
base = 16;
break;
case 'b': /* hex or binary */
if (mode & MODE_HEX)
base = 16;
else
{
base = 2;
p++;
}
break;
case 'd': /* hex or decimal */
if (mode & MODE_HEX)
base = 16;
else
{
base = 10;
p++;
}
break;
default:
break;
}
/*
* now p points to start of string to convert and base hold its base
* number 2, 8, 10 or 16
*/
if (!base)
return (0);
if (*p == '-')
{
sign = -1;
p++;
}
while (tolower (*p))
{
for (i = 0; i < base; i++)
if (*p == hexas[i])
{
result = result * base + i;
break;
}
if (i >= base)
{
/* unknown char has occurred, return value or error */
if (strchr (",-+()", *p) || isspace (*p))
i = 0;
else if (!level && !(mode & MODE_QUERY))
printf ("Bad character near '%s'\n", p);
break;
}
p++;
}
/* printf ("mode %02X last %d base %d value %d\n",
mode, i, base, result); */
/* return final value */
return ((mode & MODE_QUERY) ? (i < base) : result * sign);
}
/*
* Base conversions.
* (+) -%&#$
*/
void
show_bases (char *line, int mode)
{
char buf[20];
int temparg = sconv (line, 0, mode);
strcpy (buf, sprint_binary (UPPER (temparg)));
printf ("\n %17x x\n %17d d\n %17o o\n %s %s b\n\n",
temparg, temparg, temparg, buf,
sprint_binary (LOWER (temparg)));
}
/*
* show prints PSW and contents of registers.
*/
void
show (void)
{
printf ("PC=%04X AC=%02X XR=%02X YR=%02X PF=%s SP=%02X %03X %3d %s\n",
(int) PC, (int) AC, (int) XR, (int) YR,
sprint_status (), (int) SP,
LOAD (PC), LOAD (PC), sprint_opcode (PC, 1));
}
void
print_stack (UBYTE sp)
{
int i;
printf ("Stack: ");
for (i = 0x101 + sp; i < 0x200; i += 2)
printf ("%02X%02X ", dbgRead (i + 1), dbgRead (i));
printf ("\n");
}
char
*
sprint_binary (UBYTE code)
{
static char bin[9];
int i;
bin[8] = 0; /* Terminator. */
for (i = 0; i < 8; i++)
{
bin[i] = (code & 128) ? '1' : '0';
code <<= 1;
}
return bin;
}
/* ------------------------------------------------------------------------- */
char
*
sprint_ophex (ADDRESS p)
{
static char hexbuf[20];
char *bp;
int j, len;
len = clength[lookup[DLOAD (p)].addr_mode];
*hexbuf = '\0';
for (j = 0, bp = hexbuf; j < 3; j++, bp += 3)
{
if (j < len)
{
sprintf (bp, "%02X ", DLOAD (p + j));
}
else
{
strcat (bp, " ");
}
}
return hexbuf;
}
/* sprint_opcode parameters:
* string the name of the machine instruction
* addr_mode # describing used addressing mode, see "vmachine.h"
* base if 1==base => HEX, 0==base => DEC, see code
* opcode address of memory where machine instruction
* and argument are. First byte is unused, because
* it is the machine code and it is already known -
* string!
*/
char
*
sprint_opcode (ADDRESS counter, int base)
{
UBYTE x = DLOAD (counter);
UBYTE p1 = DLOAD (counter + 1);
UBYTE p2 = DLOAD (counter + 2);
return sprint_disassembled (counter, x, p1, p2, base);
}
char
*
sprint_disassembled (ADDRESS counter, UBYTE x, UBYTE p1, UBYTE p2, int base)
{
char *string;
int addr_mode;
char *buffp;
static char buff[20];
int ival;
ival = p1 & 0xFF;
buffp = buff;
string = lookup[x].mnemonic;
addr_mode = lookup[x].addr_mode;
sprintf (buff, "%s", string); /* Print opcode. */
while (*++buffp);
switch (addr_mode)
{
/*
* Bits 0 and 1 are usual marks for X and Y indexed addresses, i.e.
* if bit #0 is set addressing mode is X indexed something and if
* bit #1 is set addressing mode is Y indexed something. This is not
* from MOS6502, but convention used in this program. See
* "vmachine.h" for details.
*/
/* Print arguments of the machine instruction. */
case IMPLIED:
break;
case ACCUMULATOR:
sprintf (buffp, " A");
break;
case IMMEDIATE:
sprintf (buffp, ((base & HEX) ? " #$%02X" : " %3d"), ival);
break;
case ZERO_PAGE:
sprintf (buffp, ((base & HEX) ? " $%02X" : " %3d"), ival);
break;
case ZERO_PAGE_X:
sprintf (buffp, ((base & HEX) ? " $%02X,X" : " %3d,X"), ival);
break;
case ZERO_PAGE_Y:
sprintf (buffp, ((base & HEX) ? " $%02X,Y" : " %3d,Y"), ival);
break;
case ABSOLUTE:
ival |= ((p2 & 0xFF) << 8);
sprintf (buffp, ((base & HEX) ? " $%04X" : " %5d"), ival);
break;
case ABSOLUTE_X:
ival |= ((p2 & 0xFF) << 8);
sprintf (buffp, ((base & HEX) ? " $%04X,X" : " %5d,X"), ival);
break;
case ABSOLUTE_Y:
ival |= ((p2 & 0xFF) << 8);
sprintf (buffp, ((base & HEX) ? " $%04X,Y" : " %5d,Y"), ival);
break;
case INDIRECT_X:
sprintf (buffp, ((base & HEX) ? " ($%02X,X)" : " (%3d,X)"), ival);
break;
case INDIRECT_Y:
sprintf (buffp, ((base & HEX) ? " ($%02X),Y" : " (%3d),Y"), ival);
break;
case ABS_INDIRECT:
ival |= ((p2 & 0xFF) << 8);
sprintf (buffp, ((base & HEX) ? " ($%04X)" : " (%5d)"), ival);
break;
case RELATIVE:
if (0x80 & ival)
ival -= 256;
ival += counter;
ival += 2;
sprintf (buffp, ((base & HEX) ? " $%04X" : " %5d"), ival);
break;
}
return buff;
}
int
eff_address (ADDRESS counter, int step)
{
int addr_mode, eff;
UBYTE x = LOAD (counter);
UBYTE p1 = 0;
ADDRESS p2 = 0;
addr_mode = lookup[x].addr_mode;
switch (clength[addr_mode])
{
case 2:
p1 = LOAD (counter + 1);
break;
case 3:
p2 = LOAD (counter + 1) | (LOAD (counter + 2) << 8);
break;
}
switch (addr_mode)
{
case IMPLIED:
case ACCUMULATOR:
eff = -1;
break;
case IMMEDIATE:
eff = -1;
break;
case ZERO_PAGE:
eff = p1;
break;
case ZERO_PAGE_X:
eff = (p1 + XR) & 0xff;
break;
case ZERO_PAGE_Y:
eff = (p1 + YR) & 0xff;
break;
case ABSOLUTE:
eff = p2;
break;
case ABSOLUTE_X:
eff = p2 + XR;
break;
case ABSOLUTE_Y:
eff = p2 + YR;
break;
case ABS_INDIRECT: /* loads 2-byte address */
eff = p2;
break;
case INDIRECT_X:
eff = LOAD_ZERO_ADDR (p1 + XR);
break;
case INDIRECT_Y:
eff = LOAD_ZERO_ADDR (p1) + YR;
break;
case RELATIVE:
eff = REL_ADDR (counter + 2, p1);
break;
default:
eff = -1;
}
return eff;
}
/* ------------------------------------------------------------------------- */
char
*
xstrdup (char *str)
{
char *t = (char *) malloc (strlen (str) + 1);
strcpy (t, str);
return (t);
}
char
*
strndup (char *str, int n)
{
char *t = (char *) malloc (n + 1);
strncpy (t, str, n);
t[n] = '\0';
return (t);
}
void
memmov (char *target, char *source, unsigned int length)
{
if (target > source)
{
target += length;
source += length;
while (length--)
*--target = *--source;
}
else if (target < source)
{
while (length--)
*target++ = *source++;
}
}